package com.example.duihua.websocket;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.netty.channel.Channel;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Component
public class WebSocketSessionManager {

    private static final Logger logger = LoggerFactory.getLogger(WebSocketSessionManager.class);
    
    // 用户ID -> Channel映射
    private final Map<Long, Channel> userChannels = new ConcurrentHashMap<>();
    
    // 群组ID -> 用户ID集合映射
    private final Map<Long, Map<Long, Boolean>> groupUsers = new ConcurrentHashMap<>();
    
    private final ObjectMapper objectMapper = new ObjectMapper();
    
    /**
     * 注册用户会话
     * @param userId 用户ID
     * @param channel 通道
     */
    public void register(Long userId, Channel channel) {
        userChannels.put(userId, channel);
        logger.info("用户会话注册: {}", userId);
    }
    
    /**
     * 注销用户会话
     * @param userId 用户ID
     */
    public void unregister(Long userId) {
        userChannels.remove(userId);
        logger.info("用户会话注销: {}", userId);
    }
    
    /**
     * 加入群组
     * @param userId 用户ID
     * @param groupId 群组ID
     */
    public void joinGroup(Long userId, Long groupId) {
        groupUsers.computeIfAbsent(groupId, k -> new ConcurrentHashMap<>()).put(userId, true);
        logger.info("用户加入群组: {} -> {}", userId, groupId);
    }
    
    /**
     * 离开群组
     * @param userId 用户ID
     * @param groupId 群组ID
     */
    public void leaveGroup(Long userId, Long groupId) {
        Map<Long, Boolean> users = groupUsers.get(groupId);
        if (users != null) {
            users.remove(userId);
            if (users.isEmpty()) {
                groupUsers.remove(groupId);
            }
        }
        logger.info("用户离开群组: {} -> {}", userId, groupId);
    }
    
    /**
     * 发送消息给指定用户
     * @param userId 用户ID
     * @param message 消息内容
     */
    public void sendToUser(Long userId, Object message) {
        Channel channel = userChannels.get(userId);
        if (channel != null && channel.isActive()) {
            try {
                channel.writeAndFlush(new TextWebSocketFrame(objectMapper.writeValueAsString(message)));
            } catch (Exception e) {
                logger.error("发送消息给用户失败: {}", userId, e);
            }
        }
    }
    
    /**
     * 发送消息给群组中的所有用户（除了发送者）
     * @param groupId 群组ID
     * @param message 消息内容
     * @param excludeUserId 排除的用户ID（通常是发送者）
     */
    public void sendToGroup(Long groupId, Object message, Long excludeUserId) {
        Map<Long, Boolean> users = groupUsers.get(groupId);
        if (users != null) {
            try {
                String messageStr = objectMapper.writeValueAsString(message);
                users.keySet().stream()
                        .filter(userId -> !userId.equals(excludeUserId))
                        .forEach(userId -> {
                            Channel channel = userChannels.get(userId);
                            if (channel != null && channel.isActive()) {
                                channel.writeAndFlush(new TextWebSocketFrame(messageStr));
                            }
                        });
            } catch (Exception e) {
                logger.error("发送消息给群组失败: {}", groupId, e);
            }
        }
    }
    
    /**
     * 广播用户状态变化
     * @param userId 用户ID
     * @param status 状态
     */
    public void broadcastStatus(Long userId, String status) {
        try {
            Map<String, Object> statusData = new HashMap<>();
            statusData.put("userId", userId);
            statusData.put("status", status);
            statusData.put("timestamp", System.currentTimeMillis());
            
            Map<String, Object> statusMessage = new HashMap<>();
            statusMessage.put("type", "STATUS");
            statusMessage.put("data", statusData);
            
            String messageStr = objectMapper.writeValueAsString(statusMessage);
            
            // 向所有在线用户广播状态变化
            userChannels.forEach((uid, channel) -> {
                if (!uid.equals(userId) && channel.isActive()) {
                    channel.writeAndFlush(new TextWebSocketFrame(messageStr));
                }
            });
        } catch (Exception e) {
            logger.error("广播状态失败: {}", userId, e);
        }
    }
    
    /**
     * 获取在线用户数量
     * @return 在线用户数量
     */
    public int getOnlineCount() {
        return userChannels.size();
    }
    
    /**
     * 检查用户是否在线
     * @param userId 用户ID
     * @return 是否在线
     */
    public boolean isOnline(Long userId) {
        Channel channel = userChannels.get(userId);
        return channel != null && channel.isActive();
    }
}